#pragma once

#include<iostream>
#include<string>
#include<cstdlib>
#include<cstring>
#include<errno.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>


const std::string gcommfile="./fifo";

#define ForRead 1
#define ForWrite 2

class Fifo
{
public:
    Fifo(const std::string& commfile=gcommfile)
    :_commfile(commfile)
    ,_mode(0666)
    ,_fd(-1)
    {}

    //1.创建管道
    void Bulid()
    {
        if(IsExists())
            return;
        
        int n=mkfifo(_commfile.c_str(),_mode);
        if(n<0)
        {
            std::cerr<<"mkfifo error: "<<strerror(errno)<<"errno: "<<errno<<std::endl;
            exit(1);
        }
        std::cerr<<"mkfifo sucess: "<<strerror(errno)<<"errno: "<<errno<<std::endl;
    }

    //2.打开管道
    void Open(int openmode)
    {
        if(openmode==ForRead)
        {
            _fd=open(_commfile.c_str(),O_RDONLY);
        }
        else if(openmode==ForWrite)
        {
            _fd=open(_commfile.c_str(),O_WRONLY);
        }
        else
        {
            std::cerr<<"fifo openmode error"<<std::endl;
        }

        if(_fd<0)
        {
            std::cerr<<"open error: "<<strerror(errno)<<"errno: "<<errno<<std::endl;
            exit(2);
        }
        else
        {
            std::cout<<"open file success"<<std::endl;
        }
    }

    //3.向管道写入
    void Send(std::string msgin)
    {
        msgin+='\n';
        // std::cout<<"msgin "<<msgin<<std::endl;
        ssize_t n=write(_fd,msgin.c_str(),msgin.size());
        (void)n;
    }

    //约定分隔符（'\n'）
    #define DELIMITER '\n'

    //4.从管道读取
    int Recv(std::string& msgout)
    {
        
        char buffer[128];
        int count=0;
        int n=0;
        msgout.clear();

        while(true)
        {
            // std::cout<<"read front"<<std::endl;
            n = read(_fd,buffer,sizeof(buffer) - 1);
            // std::cout<<"read back"<<std::endl;
            if(n>0)
            {
                buffer[n] = '\0';
                // std::cout<<n<<std::endl;
                count+=n;
                msgout+=buffer;

                size_t last = msgout.size() - 1;
                if (last >= 0 && msgout[last] == DELIMITER)
                {
                    msgout.erase(last); 
                    // std::cout<<count-1<<std::endl;
                    return count-1;
                }
                // std::cout<<msgout[msgout.size()-1]<<std::endl;
            }
            else if(n==0)
            {
                return count;
            }
            else
            {
                msgout.clear();
                return -1;
            }
        }

        // char buffer[128];
        // ssize_t n = read(_fd, buffer, sizeof(buffer)-1); // 为什么要-1？
        // if(n > 0)
        // {
        //     buffer[n] = 0;
        //     msgout.clear();
        //     msgout += buffer;
        //     return n;
        // }
        // else if(n == 0)
        // {
        //     return 0;
        // }
        // else
        // {
        //     return -1;
        // }


    }

    //5.删除管道
    void Delet()
    {
        if(!IsExists())
            return;
        int n=unlink(_commfile.c_str());
        if(n<0)
        {
            std::cerr<<"unlink error: "<<strerror(errno)<<"errno: "<<errno<<std::endl;
            return;
        }
        std::cout<<"Unlink "<<_commfile<<std::endl;
    }

    ~Fifo(){}

private:

    bool IsExists()
    {
        struct stat st;
        int n=stat(_commfile.c_str(),&st);
        if(n==0)
        {
            std::cout<<"file exists"<<std::endl;
            return true;
        }
        else
        {
            errno=0;
            std::cout<<"file not exists"<<std::endl;
            return false;
        }
    }

private:
    std::string _commfile; //管道文件路径和文件名
    mode_t _mode;          //管道文件创建时的权限
    int _fd;                //打开管道文件后的文件操作符
};